<?php


namespace app\queue\stomp;

use app\queue\BaseConsumer;
use common\model\TaskModel;
use common\model\TaskRelationModel;
use common\model\TaskRelationTagModel;
use common\service\CommonService;
use common\service\TaskUpstreamService;
use Webman\Stomp\RetryAbleConsumer;

/**
 * 创建模板待办
 * 填充上游任务id 到 task.json
 */
class TaskCreateTemplateTodoFixUpstreamTaskIds extends BaseConsumer implements RetryAbleConsumer
{

    // 要消费的队列名
    public $queue = 'task_create_template_todo_fix_upstream_task_ids';

    // 连接名，对应 config/redis_queue.php 里的连接`
    public $connection = 'default';

    /**
     * 监听模板待办创建
     * @param $data
     * @return void
     * @throws \Exception
     */
    public function doConsume($data)
    {
        if ($data['step_type'] == TaskModel::STEP_TYPE_STEP) {
            return;
        }
        $data['json'] = json_decode($data['json'], true);
        // 1.查询当前代办任务模板配置
        if (empty($data['json']['template_todo_info']['id'])) {
            return;
        }
        $templateTodoId = $data['json']['template_todo_info']['id'];
        $tempLateTaskUpstreamInfo = TaskUpstreamService::getInstance()->getStandardTempLateTaskUpstreamInfo($data, $templateTodoId);

        // 2.通过模板配置匹配到上游任务ids
        $toDoTargetIds = array_column($tempLateTaskUpstreamInfo['to_do_target_id_list'] ?? [], 'target_id');
        $stepTargetIds = array_column($tempLateTaskUpstreamInfo['step_target_id_list'] ?? [], 'target_id');

        // 3.更新上游任务ids到 task.json
        $getUpstreamTaskIdInfo = $this->getDownUpstreamTaskIds($data, $toDoTargetIds, $stepTargetIds);
        $upstreamTaskIds = array_merge($getUpstreamTaskIdInfo['todo_task_ids'] ?? [], $getUpstreamTaskIdInfo['step_task_ids'] ?? []);
        if (!empty($upstreamTaskIds)) {
            $this->updateTaskJson($data, $upstreamTaskIds); // 更新task.json
            // 增加任务关联关系
//            TaskUpstreamService::getInstance()->addTaskUpstream($data['id'], $upstreamTaskIds);
        }

        /**
         * 因为有时候会存在 我的上游后创建，所有有此步骤，比如 layout一审剪辑整理先创建，动画layout 一审提交后创建
         * 所以，要把 动画layout一审提交的下游 补充 到 layout一审剪辑整理 的下游任务里
         */
        // 4.把我补到下游任务里面
        $toDoSourceIds = array_column($tempLateTaskUpstreamInfo['to_do_source_id_list'] ?? [], 'source_id');
        $getDownstreamTaskInfo = $this->getDownUpstreamTaskIds($data, $toDoSourceIds, []);
        $downstreamTaskIds = $getDownstreamTaskInfo['todo_task_ids'] ?? [];
        if (!empty($downstreamTaskIds)) {
            // 把'当前任务id'补充到 json.upstream_task_ids 配置里面
            foreach ($downstreamTaskIds as $taskId) {
                $updateWhere['id'] = $taskId;
                // 更新task.json
                $this->updateTaskJson($updateWhere, [$data['id']]);
                // 增加任务关联关系
//                TaskUpstreamService::getInstance()->addTaskUpstream($taskId, [$data['id']]);
            }
        }
    }


    /**
     * 组织上游任务数据，区分上游【标准 to_do】任务列表、上游【工序 step】任务列表
     * @param $task
     * @param $todoIds
     * @param $stepIds
     * @return array[]
     */
    public function getDownUpstreamTaskIds($task, $todoIds, $stepIds)
    {
        // 标准：模板task_type类型为 to_do
        $todoUpstreamTaskIds = [];
        if (!empty($todoIds)) {
            // 关联集,所有上游标准任务（如果没有集,就不查询）
            $taskRelationEpisodeIds = model(TaskRelationTagModel::class)
                ->where(['task_id' => $task['id'], 'link_module_code' => 'episode'])
                ->field('link_id')
                ->column('link_id');
            if (!empty($taskRelationEpisodeIds)) {
                // 拿到上面步骤查出来的 target_id 列表,查出所有的上游任务
                $todoUpstreamTaskIds = model(TaskModel::class)
                    ->join("task_relation_tag trg on trg.task_id = task.id and trg.link_module_code = 'episode'")
                    ->field('task.id as task_id')
                    ->where(['task.project_id' => $task['project_id']])
                    ->where(['trg.link_id' => ['IN', $taskRelationEpisodeIds]])
                    ->where(['task.step_id' => ['IN', $todoIds]])
                    ->where(['task.step_type' => ['IN', ['to_do', 'standard_meeting', 'standard_review']]])
                    ->column('task_id');
            }
        }
        // 工序：模板task_type类型为 step
        $stepUpstreamTaskIds = [];
        if (!empty($stepIds)) {
            // 关联集，所有上游工序任务(资产初始集/使用集)
            $taskRelationEpisodeIds = model(TaskRelationTagModel::class)
                ->where(['task_id' => $task['id'], 'link_module_code' => 'episode'])
                ->field('link_id')
                ->column('link_id');
            if (!empty($taskRelationEpisodeIds)) {
                // 拿到上面步骤查出来的 target_id 列表,查出所有的上游任务
                $stepUpstreamTaskIds = model(TaskModel::class)
                    ->join("task_relation_tag trg on trg.task_id = task.id and trg.link_module_code = 'episode'")
                    ->field('task.id as task_id')
                    ->where(['trg.link_id' => ['IN', $taskRelationEpisodeIds]])
                    ->where(['task.project_id' => $task['project_id']])
                    ->where(['task.step_id' => ['IN', $stepIds]])
                    ->where(['task.step_type' => ['IN', ['to_do', 'standard_meeting', 'standard_review']]])
                    ->column('task_id');
            }
        }
        return ['todo_task_ids' => $todoUpstreamTaskIds, 'step_task_ids' => $stepUpstreamTaskIds];
    }


    /**
     * 更新上游任务ids到 task.json
     * @param $data
     * @param $toDoTargetIds
     * @return void
     * @throws \Exception
     */
    public function updateTaskJson($data, $toDoTargetIds)
    {
        if (empty($data['id'])) {
            return;
        }
        // 如果原来有上游任务id,则合并之前的
        $upstreamTaskInfo = model(TaskModel::class)
            ->where(['id' => $data['id']])
            ->field([
                "JSON_UNQUOTE(JSON_EXTRACT(json, '$.upstream_task_ids')) as upstream_task_ids"
            ])
            ->find();
        $oldUpstreamTaskIds = json_decode($upstreamTaskInfo['upstream_task_ids'] ?? '{}', true);
        $newUpstreamTaskIds = array_merge($oldUpstreamTaskIds, $toDoTargetIds);
        if (empty($newUpstreamTaskIds)) {
            return;
        }
        $updateData = [
            'id' => $data['id'],
            'upstream_task_ids' => array_unique($newUpstreamTaskIds)
        ];
        CommonService::instance('task')->update($updateData);
    }

    /**
     * 重试间隔
     * @return int
     */
    public function getTtr()
    {
        return 60;
    }

    /**
     * 能否重试
     * @param $attempt
     * @param $error
     * @return bool
     */
    public function canRetry($attempt, $error)
    {
        trace(format_exception_info($error), 'ERR');
        return $attempt <= 5;
    }
}
